#pragma once
#include <cuda_runtime.h>
#include <glm/glm.hpp>

namespace PhysLeo {

/**
 * peridynamic anisotropic linear material.
 * \f$ g=h=(x-1)^2 , G=|R\sum v|\f$.
 * R is a rotation matrix, \f$\sum\f$ is a diagnal matrix, v is original bond direction.
 */
template<typename T>
class PdmAniso {
public:
    /**
    * g function in Pdm anisotropic linear material is (x-1)^2
    * @param[in] x  a T value describe the deformation severity
    * @param[in] ptr_material  a pointer to vertex specific material data
    * @return T value
    */
    __host__ __device__ static T gFunction(T x, T* ptr_material)
    {
        return (x - 1)*(x - 1);
    }

    /**
    * h function in Pdm anisotropic linear material is (x-1)^2
    * @param[in] x  a T value describe the deformation severity
    * @param[in] ptr_material  a pointer to vertex specific material data
    * @return T value
    */
    __host__ __device__ static T hFunction(T x, T* ptr_material)
    {
        return (x - 1)*(x - 1);
    }

    /**
    * first derivative of g function in Pdm anisotropic linear material is 2*(x-1)
    * @param[in] x  a T value describe the deformation severity
    * @param[in] ptr_material  a pointer to vertex specific material data
    * @return T value
    */
    __host__ __device__ static T dgFunction(T x, T* ptr_material)
    {
        return 2 * (x - 1);
    }

    /**
    * first derivative of h function in Pdm anisotropic linear material is 2*(x-1)
    * @param[in] x  a T value describe the deformation severity
    * @param[in] ptr_material  a pointer to vertex specific material data
    * @return T value
    */
    __host__ __device__ static T dhFunction(T x, T* ptr_material)
    {
        return 2 * (x - 1);
    }

    /**
    * first derivative of g function in Pdm anisotropic linear material is 2
    * @param[in] x  a T value describe the deformation severity
    * @param[in] ptr_material  a pointer to vertex specific material data
    * @return T value
    */
    __host__ __device__ static T ddgFunction(T x, T* ptr_material)
    {
        return 2.0f;
    }

    /**
    * first derivative of h function in Pdm anisotropic linear material is 2
    * @param[in] x  a T value describe the deformation severity
    * @param[in] ptr_material  a pointer to the specific vertex material data
    * @return T value
    */
    __host__ __device__ static T ddhFunction(T x, T* ptr_material)
    {
        return 2.0f;
    }

    /**
    * anisotropic weight function in Pdm anisotropic linear material, |Gv|.
    * G is the 3x3 anisotropic matrix, it can be construct by \f$ R\sum \f$, R is rotation matrix represents three main direction, \f$ \sum \f$ is diagonal matrix represents the specific intensity in different direction.
    * @param[in] direction  a vec3<T> value describe the material direction
    * @param[in] ptr_material  a pointer to the specific vertex material data
    * @return T value
    */
    __host__ __device__ static T anisoWeight(glm::tvec3<T> direction, T* ptr_material)
    {
        auto aniso = glm::tmat3x3<T>(
            ptr_material[2], ptr_material[3], ptr_material[4],
            ptr_material[5], ptr_material[6], ptr_material[7],
            ptr_material[8], ptr_material[9], ptr_material[10]);

        return glm::length(aniso*direction);
    }
};

}